νμ μμ ν μ±κΈ μ¬μΈμ¨(SSO) μΈμ¦ μμ€ν κ΅¬μΆ μ TypeScriptμ μ΄μ μ μ΄ν΄λ³΄μΈμ. 보μ κ°ν, μ€λ₯ κ°μ, λ€μν μ ν리μΌμ΄μ μ λ°μ μ μ§λ³΄μμ± ν₯μ.
TypeScript μ±κΈ μ¬μΈμ¨: μΈμ¦ μμ€ν νμ μΈμ΄νν°
μ€λλ μνΈ μ°κ²°λ λμ§νΈ νκ²½μμ μ±κΈ μ¬μΈμ¨(SSO)μ νλ μ ν리μΌμ΄μ 보μμ μ΄μμ΄ λμμ΅λλ€. μ¬μ©μ μΈμ¦μ κ°μννμ¬ μνν κ²½νμ μ 곡νκ³ μ¬λ¬ μ격 μ¦λͺ μ κ΄λ¦¬νλ λΆλ΄μ μ€μ λλ€. κ·Έλ¬λ κ°λ ₯νκ³ μμ ν SSO μμ€ν μ ꡬμΆνλ €λ©΄ μ μ€ν κ³νκ³Ό ꡬνμ΄ νμν©λλ€. μ¬κΈ°μ κ°λ ₯ν νμ μμ€ν μ κ°μΆ TypeScriptλ μΈμ¦ μΈνλΌμ μμ μ±κ³Ό μ μ§λ³΄μμ±μ ν¬κ² ν₯μμν¬ μ μμ΅λλ€.
μ±κΈ μ¬μΈμ¨(SSO)μ΄λ 무μμΈκ°μ?
SSOλ₯Ό μ¬μ©νλ©΄ μ¬μ©μλ λ¨μΌ λ‘κ·ΈμΈ μ격 μ¦λͺ μΈνΈλ‘ κ΄λ ¨λμ§λ§ λ 립μ μΈ μ¬λ¬ μννΈμ¨μ΄ μμ€ν μ μ‘μΈμ€ν μ μμ΅λλ€. μ¬μ©μμκ² κ° μ ν리μΌμ΄μ μ λν λ³λμ μ¬μ©μ μ΄λ¦κ³Ό λΉλ°λ²νΈλ₯Ό κΈ°μ΅νκ³ κ΄λ¦¬νλλ‘ μꡬνλ λμ , SSOλ μ λ’°ν μ μλ ID 곡κΈμ(IdP)λ₯Ό ν΅ν΄ μΈμ¦ νλ‘μΈμ€λ₯Ό μ€μ μ§μ€νν©λλ€. μ¬μ©μκ° SSOλ‘ λ³΄νΈλλ μ ν리μΌμ΄μ μ μ‘μΈμ€νλ €κ³ νλ©΄ μ ν리μΌμ΄μ μ μΈμ¦μ μν΄ μ¬μ©μλ₯Ό IdPλ‘ λ¦¬λλ μ ν©λλ€. μ¬μ©μκ° μ΄λ―Έ IdPμ μΈμ¦λ κ²½μ° μ ν리μΌμ΄μ μ μννκ² μ‘μΈμ€ κΆνμ΄ λΆμ¬λ©λλ€. κ·Έλ μ§ μμΌλ©΄ λ‘κ·ΈμΈμ μμ²λ°μ΅λλ€.
μΈκΈ° μλ SSO νλ‘ν μ½μ λ€μκ³Ό κ°μ΅λλ€:
- OAuth 2.0: μ£Όλ‘ κΆν λΆμ¬ νλ‘ν μ½μΈ OAuth 2.0μ μ ν리μΌμ΄μ μ΄ μ¬μ©μ μ격 μ¦λͺ μ μꡬνμ§ μκ³ μ¬μ©μ λμ 보νΈλ 리μμ€μ μ‘μΈμ€ν μ μλλ‘ ν©λλ€.
- OpenID Connect (OIDC): OAuth 2.0 μμ ꡬμΆλ ID κ³μΈ΅μΌλ‘, μ¬μ©μ μΈμ¦ λ° ID μ 보λ₯Ό μ 곡ν©λλ€.
- SAML 2.0: μν°νλΌμ΄μ¦ νκ²½μμ μΉ λΈλΌμ°μ SSOμ μμ£Ό μ¬μ©λλ λ³΄λ€ μ±μν νλ‘ν μ½μ λλ€.
SSOμ TypeScriptλ₯Ό μ¬μ©ν΄μΌ νλ μ΄μ λ 무μμΈκ°μ?
JavaScriptμ μμ μ§ν©μΈ TypeScriptλ JavaScriptμ λμ νΉμ±μ μ μ νμ΄νμ μΆκ°ν©λλ€. μ΄λ SSOμ κ°μ 볡μ‘ν μμ€ν μ ꡬμΆνλ λ° μ¬λ¬ κ°μ§ μ΄μ μ μ 곡ν©λλ€:
1. ν₯μλ νμ μΈμ΄νν°
TypeScriptμ μ μ νμ΄νμ μ¬μ©νλ©΄ JavaScriptμμ λ°νμμ λνλ μ μλ μ€λ₯λ₯Ό κ°λ° μ€μ λ°κ²¬ν μ μμ΅λλ€. μ΄λ μΈμ¦κ³Ό κ°μ΄ μ¬μν μ€λ₯λΌλ μ¬κ°ν κ²°κ³Όλ₯Ό μ΄λν μ μλ 보μμ λ―Όκ°ν μμμμ νΉν μ€μν©λλ€. μλ₯Ό λ€μ΄, μ¬μ©μ IDκ° νμ λ¬Έμμ΄μμ 보μ₯νκ±°λ μΈμ¦ ν ν°μ΄ νΉμ νμμ μ€μν¨μ 보μ₯νλ κ²μ TypeScriptμ νμ μμ€ν μ ν΅ν΄ μνλ μ μμ΅λλ€.
μ:
interface User {
id: string;
email: string;
firstName: string;
lastName: string;
}
function authenticateUser(credentials: Credentials): User {
// ...μΈμ¦ λ‘μ§...
const user: User = {
id: "user123",
email: "test@example.com",
firstName: "John",
lastName: "Doe",
};
return user;
}
// idμ μ«μλ₯Ό ν λΉνλ €κ³ νλ©΄ μ€λ₯ λ°μ
// const invalidUser: User = { id: 123, email: "...", firstName: "...", lastName: "..." };
2. ν₯μλ μ½λ μ μ§λ³΄μμ±
SSO μμ€ν μ΄ λ°μ νκ³ μ±μ₯ν¨μ λ°λΌ TypeScriptμ νμ μ£Όμμ μ½λλ² μ΄μ€λ₯Ό μ΄ν΄νκ³ μ μ§λ³΄μνκΈ° μ½κ² λ§λλλ€. νμ μ λ¬Έμ μν μ νμ¬ λ°μ΄ν°μ μμ ꡬ쑰μ ν¨μμ λμμ λͺ νν ν©λλ€. μ»΄νμΌλ¬κ° μ μ¬μ μΈ νμ λΆμΌμΉλ₯Ό μλ³ν μ μμΌλ―λ‘ λ¦¬ν©ν λ§μ΄ λ μμ νκ³ μ€λ₯ λ°μ κ°λ₯μ±μ΄ μ€μ΄λλλ€.
3. λ°νμ μ€λ₯ κ°μ
μ»΄νμΌ μ€μ νμ κ΄λ ¨ μ€λ₯λ₯Ό κ°μ§ν¨μΌλ‘μ¨ TypeScriptλ λ°νμ μμΈ λ°μ κ°λ₯μ±μ ν¬κ² μ€μ λλ€. μ΄λ λ μμ μ μ΄κ³ μ λ’°ν μ μλ SSO μμ€ν μΌλ‘ μ΄μ΄μ Έ μ¬μ©μ λ° μ ν리μΌμ΄μ μ€λ¨μ μ΅μνν©λλ€.
4. λ λμ λꡬ λ° IDE μ§μ
TypeScriptμ νλΆν νμ μ 보λ μ½λ μμ±, 리ν©ν λ§ λꡬ, μ μ λΆμκ³Ό κ°μ κ°λ ₯ν λꡬλ₯Ό μ§μν©λλ€. Visual Studio Codeμ κ°μ μ΅μ IDEλ μ°μν TypeScript μ§μμ μ 곡νμ¬ κ°λ°μ μμ°μ±μ ν₯μμν€κ³ μ€λ₯λ₯Ό μ€μ λλ€.
5. ν₯μλ νμ
TypeScriptμ λͺ μμ μΈ νμ μμ€ν μ κ°λ°μ κ°μ λ λμ νμ μ μ΄μ§ν©λλ€. νμ μ λ°μ΄ν° ꡬ쑰 λ° ν¨μ μλͺ μ λν λͺ νν κ³μ½μ μ 곡νμ¬ λͺ¨νΈμ±μ μ€μ΄κ³ ν λ΄ μμ¬μν΅μ κ°μ ν©λλ€.
TypeScriptλ‘ νμ μμ ν SSO μμ€ν ꡬμΆ: μ€μ©μ μΈ μμ
TypeScriptλ₯Ό μ¬μ©νμ¬ OpenID Connect (OIDC)μ μ€μ μ λ μ€μ©μ μΈ μμ λ₯Ό ν΅ν΄ νμ μμ ν SSO μμ€ν μ ꡬμΆνλ λ°©λ²μ 보μ¬λλ¦¬κ² μ΅λλ€.
1. OIDC κ°μ²΄μ λν μΈν°νμ΄μ€ μ μ
λ¨Όμ λ€μκ³Ό κ°μ μ£Όμ OIDC κ°μ²΄λ₯Ό λνλ΄λ TypeScript μΈν°νμ΄μ€λ₯Ό μ μνλ κ²μΌλ‘ μμν©λλ€:
- κΆν λΆμ¬ μμ²: κΆν λΆμ¬ μλ²λ‘ μ μ‘λλ μμ²μ ꡬ쑰μ λλ€.
- ν ν° μλ΅: μ‘μΈμ€ ν ν°, ID ν ν° λ±μ ν¬ν¨νλ κΆν λΆμ¬ μλ²μ μλ΅μ λλ€.
- Userinfo μλ΅: μ¬μ©μ νλ‘ν μ 보λ₯Ό ν¬ν¨νλ userinfo μλν¬μΈνΈμ μλ΅μ λλ€.
interface AuthorizationRequest {
response_type: "code";
client_id: string;
redirect_uri: string;
scope: string;
state?: string;
nonce?: string;
}
interface TokenResponse {
access_token: string;
token_type: "Bearer";
expires_in: number;
id_token: string;
refresh_token?: string;
}
interface UserinfoResponse {
sub: string; // Subject Identifier (κ³ μ μ¬μ©μ ID)
name?: string;
given_name?: string;
family_name?: string;
email?: string;
email_verified?: boolean;
profile?: string;
picture?: string;
}
μ΄λ¬ν μΈν°νμ΄μ€λ₯Ό μ μν¨μΌλ‘μ¨ OIDC κ°μ²΄μ νμ μμ ν λ°©μμΌλ‘ μνΈ μμ©νλλ‘ μ½λλ₯Ό 보μ₯ν μ μμ΅λλ€. μμλλ ꡬ쑰μμ λ²μ΄λλ κ²μ TypeScript μ»΄νμΌλ¬μ μν΄ κ°μ§λ©λλ€.
2. νμ κ²μ¬λ₯Ό ν΅ν μΈμ¦ νλ¦ κ΅¬ν
μ΄μ TypeScriptλ₯Ό μΈμ¦ νλ¦ κ΅¬νμ μ¬μ©νλ λ°©λ²μ μ΄ν΄λ³΄κ² μ΅λλ€. ν ν° κ΅νμ μ²λ¦¬νλ ν¨μλ₯Ό κ³ λ €ν΄ λ³΄μΈμ:
async function exchangeCodeForToken(code: string, clientId: string, clientSecret: string, redirectUri: string): Promise<TokenResponse> {
const tokenEndpoint = "https://example.com/token"; // IdPμ ν ν° μλν¬μΈνΈλ‘ κ΅μ²΄νμΈμ.
const body = new URLSearchParams({
grant_type: "authorization_code",
code: code,
redirect_uri: redirectUri,
client_id: clientId,
client_secret: clientSecret,
});
const response = await fetch(tokenEndpoint, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: body,
});
if (!response.ok) {
throw new Error(`Token exchange failed: ${response.status} ${response.statusText}`);
}
const data = await response.json();
// μλ΅μ΄ TokenResponse μΈν°νμ΄μ€μ μΌμΉνλλ‘ λ³΄μ₯νλ νμ
λ¨μΈ
return data as TokenResponse;
}
`exchangeCodeForToken` ν¨μλ μμλλ μ λ ₯ λ° μΆλ ₯ νμ μ λͺ ννκ² μ μν©λλ€. `Promise<TokenResponse>` λ°ν νμ μ ν¨μκ° νμ `TokenResponse` κ°μ²΄λ‘ ν΄κ²°λλ Promiseλ₯Ό λ°νν¨μ 보μ₯ν©λλ€. νμ λ¨μΈ `data as TokenResponse`μ μ¬μ©νλ©΄ JSON μλ΅μ΄ μΈν°νμ΄μ€μ νΈνλ¨μ κ°μ ν©λλ€.
νμ λ¨μΈμ΄ λμμ΄ λκΈ°λ νμ§λ§, λ°ννκΈ° μ μ `TokenResponse` μΈν°νμ΄μ€μ λν΄ μλ΅μ κ²μ¦νλ κ²μ΄ λ κ°λ ₯ν μ κ·Ό λ°©μμ λλ€. μ΄λ `io-ts` λλ `zod`μ κ°μ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ¬ λ¬μ±ν μ μμ΅λλ€.
3. `io-ts`λ₯Ό μ¬μ©ν API μλ΅ κ²μ¦
`io-ts`λ₯Ό μ¬μ©νλ©΄ λ°νμ νμ κ²μ¦κΈ°λ₯Ό μ μνμ¬ λ°μ΄ν°κ° TypeScript μΈν°νμ΄μ€λ₯Ό μ€μνλμ§ νμΈν μ μμ΅λλ€. `TokenResponse`λ₯Ό κ²μ¦νλ λ°©λ²μ μλ λ€μκ³Ό κ°μ΅λλ€:
import * as t from 'io-ts'
import { PathReporter } from 'io-ts/PathReporter'
const TokenResponseCodec = t.type({
access_token: t.string,
token_type: t.literal("Bearer"),
expires_in: t.number,
id_token: t.string,
refresh_token: t.union([t.string, t.undefined]) // μ νμ refresh ν ν°
})
type TokenResponse = t.TypeOf<typeof TokenResponseCodec>
async function exchangeCodeForToken(code: string, clientId: string, clientSecret: string, redirectUri: string): Promise<TokenResponse> {
// ... (μ΄μ κ³Ό κ°μ Fetch API νΈμΆ)
const data = await response.json();
const validation = TokenResponseCodec.decode(data);
if (validation._tag === 'Left') {
const errors = PathReporter.report(validation);
throw new Error(`Invalid Token Response: ${errors.join('\n')}`);
}
return validation.right; // μ¬λ°λ₯΄κ² νμ
μ΄ μ§μ λ TokenResponse
}
μ΄ μμ μμ `TokenResponseCodec`μ μμ λ λ°μ΄ν°κ° μμλλ ꡬ쑰μ μΌμΉνλμ§ νμΈνλ κ²μ¦κΈ°λ₯Ό μ μν©λλ€. κ²μ¦μ΄ μ€ν¨νλ©΄ μμΈν μ€λ₯ λ©μμ§κ° μμ±λμ΄ λ¬Έμ μ μμ€λ₯Ό μλ³νλ λ° λμμ΄ λ©λλ€. μ΄ μ κ·Ό λ°©μμ κ°λ¨ν νμ λ¨μΈλ³΄λ€ ν¨μ¬ μμ ν©λλ€.
4. νμ μ΄ μ§μ λ κ°μ²΄λ₯Ό μ¬μ©ν μ¬μ©μ μΈμ μ²λ¦¬
TypeScriptλ μ¬μ©μ μΈμ μ νμ μμ ν λ°©μμΌλ‘ κ΄λ¦¬νλ λ°μλ μ¬μ©λ μ μμ΅λλ€. μΈμ λ°μ΄ν°λ₯Ό λνλ΄λ μΈν°νμ΄μ€λ₯Ό μ μν©λλ€:
interface UserSession {
userId: string;
accessToken: string;
refreshToken?: string;
expiresAt: Date;
}
// μΈμ
μ μ₯ λ©μ»€λμ¦μμ μ¬μ© μμ
function createUserSession(user: UserinfoResponse, tokenResponse: TokenResponse): UserSession {
const expiresAt = new Date(Date.now() + tokenResponse.expires_in * 1000);
return {
userId: user.sub,
accessToken: tokenResponse.access_token,
refreshToken: tokenResponse.refresh_token,
expiresAt: expiresAt,
};
}
// ... μΈμ
λ°μ΄ν°μ λν νμ
μμ μ‘μΈμ€
μΈμ λ°μ΄ν°λ₯Ό νμ μ΄ μ§μ λ κ°μ²΄λ‘ μ μ₯ν¨μΌλ‘μ¨ μ ν¨ν λ°μ΄ν°λ§ μΈμ μ μ μ₯λλλ‘ νκ³ μ ν리μΌμ΄μ μ΄ νμ μ κ°μ§κ³ μ‘μΈμ€ν μ μλλ‘ ν μ μμ΅λλ€.
κ³ κΈ TypeScript SSO
1. μ¬μ¬μ© κ°λ₯ν κ΅¬μ± μμλ₯Ό μν μ λ€λ¦ μ¬μ©
μ λ€λ¦μ μ¬μ©νλ©΄ λ€λ₯Έ μ νμ λ°μ΄ν°μ ν¨κ» μλνλ μ¬μ¬μ© κ°λ₯ν κ΅¬μ± μμλ₯Ό λ§λ€ μ μμ΅λλ€. μ΄λ μΌλ°μ μΈ μΈμ¦ λ―Έλ€μ¨μ΄ λλ μμ² νΈλ€λ¬λ₯Ό ꡬμΆνλ λ° νΉν μ μ©ν©λλ€.
interface RequestContext<T> {
user?: T;
// ... κΈ°ν μμ² μ»¨ν
μ€νΈ μμ±
}
// μμ² μ»¨ν
μ€νΈμ μ¬μ©μ μ 보λ₯Ό μΆκ°νλ μμ λ―Έλ€μ¨μ΄
function withUser<T extends UserinfoResponse>(handler: (ctx: RequestContext<T>) => Promise<void>) {
return async (req: any, res: any) => {
// ...μΈμ¦ λ‘μ§...
const user: T = await fetchUserinfo() as T; // fetchUserinfoλ μ¬μ©μ μ 보λ₯Ό κ²μν©λλ€.
const ctx: RequestContext<T> = { user: user };
return handler(ctx);
};
}
2. μν κ΄λ¦¬λ₯Ό μν νλ³λ μ λμ¨
νλ³λ μ λμ¨μ SSO μμ€ν μ λ€λ₯Έ μνλ₯Ό λͺ¨λΈλ§νλ κ°λ ₯ν λ°©λ²μ λλ€. μλ₯Ό λ€μ΄, μΈμ¦ νλ‘μΈμ€μ λ€λ₯Έ λ¨κ³(μ: `Pending`, `Authenticated`, `Failed`)λ₯Ό λνλ΄λ λ° μ¬μ©ν μ μμ΅λλ€.
type AuthState =
| { status: "pending" }
| { status: "authenticated"; user: UserinfoResponse }
| { status: "failed"; error: string };
function renderAuthState(state: AuthState): string {
switch (state.status) {
case "pending":
return "Loading...";
case "authenticated":
return `Welcome, ${state.user.name}!`;
case "failed":
return `Authentication failed: ${state.error}`;
}
}
보μ κ³ λ € μ¬ν
TypeScriptλ νμ μΈμ΄νν°λ₯Ό ν₯μμν€κ³ μ€λ₯λ₯Ό μ€μ΄μ§λ§, λͺ¨λ 보μ λ¬Έμ λ₯Ό ν΄κ²°νλ κ²μ μλμ κΈ°μ΅νλ κ²μ΄ μ€μν©λλ€. μ¬μ ν λ€μκ³Ό κ°μ μ μ ν 보μ κ΄νμ ꡬνν΄μΌ ν©λλ€:
- μ λ ₯ μ ν¨μ± κ²μ¬: μ£Όμ 곡격μ λ°©μ§νκΈ° μν΄ λͺ¨λ μ¬μ©μ μ λ ₯μ μ ν¨μ± κ²μ¬ν©λλ€.
- μμ ν μ μ₯: API ν€ λ° λΉλ°κ³Ό κ°μ λ―Όκ°ν λ°μ΄ν°λ νκ²½ λ³μ λλ HashiCorp Vaultμ κ°μ μ μ© λΉλ° κ΄λ¦¬ μμ€ν μ μ¬μ©νμ¬ μμ νκ² μ μ₯ν©λλ€.
- HTTPS: λͺ¨λ ν΅μ μ΄ HTTPSλ₯Ό μ¬μ©νμ¬ μνΈνλλλ‘ ν©λλ€.
- μ κΈ°μ μΈ λ³΄μ κ°μ¬: μ μ¬μ μΈ μ·¨μ½μ μ μλ³νκ³ ν΄κ²°νκΈ° μν΄ μ κΈ°μ μΈ λ³΄μ κ°μ¬λ₯Ό μνν©λλ€.
- μ΅μ κΆν μμΉ: μ¬μ©μ λ° μ ν리μΌμ΄μ μ νμν κΆνλ§ λΆμ¬ν©λλ€.
- μ¬λ°λ₯Έ μ€λ₯ μ²λ¦¬: μ€λ₯ λ©μμ§μμ λ―Όκ°ν μ λ³΄κ° μ μΆλμ§ μλλ‘ ν©λλ€.
- ν ν° λ³΄μ: μΈμ¦ ν ν°μ μμ νκ² μ μ₯νκ³ κ΄λ¦¬ν©λλ€. XSS 곡격μΌλ‘λΆν° 보νΈνκΈ° μν΄ μΏ ν€μ HttpOnly λ° Secure νλκ·Έλ₯Ό μ¬μ©νλ κ²μ κ³ λ €νμΈμ.
κΈ°μ‘΄ μμ€ν κ³Όμ ν΅ν©
TypeScript κΈ°λ° SSO μμ€ν μ κΈ°μ‘΄ μμ€ν (λ€λ₯Έ μΈμ΄λ‘ μμ±λ μμ€ν ν¬ν¨)κ³Ό ν΅ν©ν λ μνΈ μ΄μ©μ± μΈ‘λ©΄μ μ μ€νκ² κ³ λ €νμμμ€. λͺ νν API κ³μ½μ μ μνκ³ JSON λλ Protocol Buffersμ κ°μ λ°μ΄ν° μ§λ ¬ν νμμ μ¬μ©νμ¬ μνν ν΅μ μ 보μ₯ν΄μΌ ν μ μμ΅λλ€.
SSOμ λν κΈλ‘λ² κ³ λ € μ¬ν
μ μΈκ³ μ¬μ©μλ₯Ό μν SSO μμ€ν μ μ€κ³νκ³ κ΅¬νν λ λ€μμ κ³ λ €νλ κ²μ΄ μ€μν©λλ€:
- νμ§ν: μ¬μ©μ μΈν°νμ΄μ€ λ° μ€λ₯ λ©μμ§μμ μ¬λ¬ μΈμ΄ λ° μ§μ μ€μ μ μ§μν©λλ€.
- λ°μ΄ν° κ°μΈ μ 보 λ³΄νΈ κ·μ : μ λ½μ GDPR, μΊλ¦¬ν¬λμμ CCPA λ° μ¬μ©μκ° μμΉν μ§μμ κΈ°ν κ΄λ ¨ λ²λ₯ μ μ€μν©λλ€.
- μκ°λ: μΈμ λ§λ£ λ° κΈ°ν μκ° κ΄λ ¨ λ°μ΄ν°λ₯Ό κ΄λ¦¬ν λ μκ°λλ₯Ό μ¬λ°λ₯΄κ² μ²λ¦¬ν©λλ€.
- λ¬Ένμ μ°¨μ΄: μ¬μ©μ κΈ°λμΉ λ° μΈμ¦ μ νΈλμ λ¬Ένμ μ°¨μ΄λ₯Ό κ³ λ €ν©λλ€. μλ₯Ό λ€μ΄, μΌλΆ μ§μμμλ λ€λ₯Έ μ§μλ³΄λ€ λ€λ¨κ³ μΈμ¦(MFA)μ λ κ°λ ₯νκ² μ νΈν μ μμ΅λλ€.
- μ κ·Όμ±: SSO μμ€ν μ΄ WCAG μ§μΉ¨μ λ°λΌ μ₯μ κ° μλ μ¬μ©μμκ² μ‘μΈμ€ κ°λ₯νμ§ νμΈν©λλ€.
κ²°λ‘
TypeScriptλ νμ μμ ν μ±κΈ μ¬μΈμ¨ μμ€ν μ ꡬμΆνλ κ°λ ₯νκ³ ν¨κ³Όμ μΈ λ°©λ²μ μ 곡ν©λλ€. μ μ νμ΄ν κΈ°λ₯μ νμ©νλ©΄ μ€λ₯λ₯Ό μ‘°κΈ°μ κ°μ§νκ³ μ½λ μ μ§λ³΄μμ±μ κ°μ νλ©° μΈμ¦ μΈνλΌμ μ λ°μ μΈ λ³΄μ λ° μμ μ±μ ν₯μμν¬ μ μμ΅λλ€. TypeScriptκ° λ³΄μμ κ°ννμ§λ§, μ§μ μΌλ‘ κ°λ ₯νκ³ μ¬μ©μ μΉνμ μΈ SSO μ루μ μ λ€μν κ΅μ μ¬μ©μμκ² μ 곡νκΈ° μν΄μλ λ€λ₯Έ 보μ λͺ¨λ² μ¬λ‘ λ° κΈλ‘λ² κ³ λ € μ¬νκ³Ό κ²°ν©νλ κ²μ΄ μ€μν©λλ€. `io-ts` λλ `zod`μ κ°μ λΌμ΄λΈλ¬λ¦¬λ₯Ό λ°νμ μ ν¨μ± κ²μ¬μ μ¬μ©νμ¬ μ ν리μΌμ΄μ μ λμ± κ°ννλ κ²μ κ³ λ €νμΈμ.
TypeScriptμ νμ μμ€ν μ μ±ννλ©΄ μ€λλ μ 볡μ‘ν λμ§νΈ νκ²½μ μꡬλ₯Ό μΆ©μ‘±νλ λ μμ νκ³ μ μ§λ³΄μ κ°λ₯νλ©° νμ₯ κ°λ₯ν SSO μμ€ν μ λ§λ€ μ μμ΅λλ€. μ ν리μΌμ΄μ μ΄ μ±μ₯ν¨μ λ°λΌ νμ μμ μ±μ μ΄μ μ λμ± λλλ¬μ Έ TypeScriptκ° κ°λ ₯ν μΈμ¦ μ루μ μ ꡬμΆνλ λͺ¨λ μ‘°μ§μκ² κ·μ€ν μμ°μ΄ λ©λλ€.